home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / gnulib / dkbtrace / pbmplus / source / ppm / giftoppm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-10  |  12.8 KB  |  568 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1990, David Koblas.                                     | */
  3. /* |   Permission to use, copy, modify, and distribute this software   | */
  4. /* |   and its documentation for any purpose and without fee is hereby | */
  5. /* |   granted, provided that the above copyright notice appear in all | */
  6. /* |   copies and that both that copyright notice and this permission  | */
  7. /* |   notice appear in supporting documentation.  This software is    | */
  8. /* |   provided "as is" without express or implied warranty.           | */
  9. /* +-------------------------------------------------------------------+ */
  10.  
  11.  
  12. #include    "ppm.h"
  13.  
  14. #define    MAXCOLORMAPSIZE        256
  15.  
  16. #define    TRUE    1
  17. #define    FALSE    0
  18.  
  19. #define CM_RED        0
  20. #define CM_GREEN    1
  21. #define CM_BLUE        2
  22.  
  23. #define    MAX_LWZ_BITS        12
  24.  
  25. #define INTERLACE        0x40
  26. #define LOCALCOLORMAP    0x80
  27. #define BitSet(byte, bit)    (((byte) & (bit)) == (bit))
  28.  
  29. #define    ReadOK(file,buffer,len)    (fread(buffer, len, 1, file) != 0)
  30.  
  31. #define LM_to_uint(a,b)            (((b)<<8)|(a))
  32.  
  33. struct {
  34.     unsigned int    Width;
  35.     unsigned int    Height;
  36.     unsigned char    ColorMap[3][MAXCOLORMAPSIZE];
  37.     unsigned int    BitPixel;
  38.     unsigned int    ColorResolution;
  39.     unsigned int    Background;
  40.     unsigned int    AspectRatio;
  41. } GifScreen;
  42.  
  43. struct {
  44.     int    transparent;
  45.     int    delayTime;
  46.     int    inputFlag;
  47.     int    disposal;
  48. } Gif89 = { -1, -1, -1, 0 };
  49.  
  50. pixel    *Image = NULL;
  51. int    verbose;
  52. int    showComment;
  53.  
  54. static char    usage[] = "[-verbose] [-comments] [-image N] [GIFfile]";
  55.  
  56. static void ReadGIF ARGS(( FILE    *fd, int imageNumber ));
  57. static int ReadColorMap ARGS(( FILE *fd, int number, unsigned char buffer[3][MAXCOLORMAPSIZE] ));
  58. static int DoExtension ARGS(( FILE *fd, int label ));
  59. static int GetDataBlock ARGS(( FILE *fd, unsigned char  *buf ));
  60. static int GetCode ARGS(( FILE *fd, int code_size, int flag ));
  61. static int LWZReadByte ARGS(( FILE *fd, int flag, int input_code_size ));
  62. static void ReadImage ARGS(( FILE *fd, int len, int height, unsigned char cmap[3][MAXCOLORMAPSIZE], int interlace, int ignore ));
  63.  
  64. void
  65. main(argc,argv)
  66. int    argc;
  67. char    **argv;
  68. {
  69.     int        argn;
  70.     FILE        *in;
  71.     int        imageNumber;
  72.  
  73.     ppm_init(&argc, argv);
  74.  
  75.     argn = 1;
  76.     imageNumber = 1;
  77.     verbose = FALSE;
  78.     showComment = FALSE;
  79.  
  80.     while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
  81.         if (pm_keymatch(argv[argn], "-verbose", 2)) {
  82.             verbose = TRUE;
  83.             showComment = TRUE;
  84.         } else if (pm_keymatch(argv[argn], "-comments", 2)) {
  85.             showComment = TRUE;
  86.         } else if (pm_keymatch(argv[argn], "-image", 2)) {
  87.             ++argn;
  88.             if (argn == argc || sscanf(argv[argn], "%d", &imageNumber) != 1)
  89.                 pm_usage(usage);
  90.         } else {
  91.             pm_usage(usage);
  92.         }
  93.         ++argn;
  94.     }
  95.     if (argn != argc) {
  96.         in = pm_openr(argv[argn]);
  97.         ++argn;
  98.     } else {
  99.         in = stdin;
  100.     }
  101.  
  102.     if (argn != argc)
  103.         pm_usage(usage);
  104.  
  105.     ReadGIF(in, imageNumber);
  106.     pm_close(in);
  107.     pm_close(stdout);
  108.     exit(0);
  109. }
  110.  
  111. static void
  112. ReadGIF(fd, imageNumber)
  113. FILE    *fd;
  114. int    imageNumber;
  115. {
  116.     unsigned char    buf[16];
  117.     unsigned char    c;
  118.     unsigned char    localColorMap[3][MAXCOLORMAPSIZE];
  119.     int        useGlobalColormap;
  120.     int        bitPixel;
  121.     int        imageCount = 0;
  122.     char        version[4];
  123.  
  124.     if (! ReadOK(fd,buf,6))
  125.         pm_error("error reading magic number" );
  126.  
  127.     if (strncmp(buf,"GIF",3) != 0)
  128.         pm_error("not a GIF file" );
  129.  
  130.     strncpy(version, buf + 3, 3);
  131.     version[3] = '\0';
  132.  
  133.     if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0))
  134.         pm_error("bad version number, not '87a' or '89a'" );
  135.  
  136.     if (! ReadOK(fd,buf,7))
  137.         pm_error("failed to read screen descriptor" );
  138.  
  139.     GifScreen.Width           = LM_to_uint(buf[0],buf[1]);
  140.     GifScreen.Height          = LM_to_uint(buf[2],buf[3]);
  141.     GifScreen.BitPixel        = 2<<(buf[4]&0x07);
  142.     GifScreen.ColorResolution = (((buf[4]&0x70)>>3)+1);
  143.     GifScreen.Background      = buf[5];
  144.     GifScreen.AspectRatio     = buf[6];
  145.  
  146.     if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
  147.         if (ReadColorMap(fd,GifScreen.BitPixel,GifScreen.ColorMap))
  148.             pm_error("error reading global colormap" );
  149.     }
  150.  
  151.     if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) {
  152.         float    r;
  153.         r = ( (float) GifScreen.AspectRatio + 15.0 ) / 64.0;
  154.         pm_message("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'",
  155.             r < 1.0 ? 'x' : 'y',
  156.             r < 1.0 ? 1.0 / r : r );
  157.     }
  158.  
  159.     for (;;) {
  160.         if (! ReadOK(fd,&c,1))
  161.             pm_error("EOF / read error on image data" );
  162.  
  163.         if (c == ';') {        /* GIF terminator */
  164.             if (imageCount < imageNumber)
  165.                 pm_error("only %d image%s found in file",
  166.                      imageCount, imageCount>1?"s":"" );
  167.             return;
  168.         }
  169.  
  170.         if (c == '!') {     /* Extension */
  171.             if (! ReadOK(fd,&c,1))
  172.                 pm_error("OF / read error on extention function code");
  173.             DoExtension(fd, c);
  174.             continue;
  175.         }
  176.  
  177.         if (c != ',') {        /* Not a valid start character */
  178.             pm_message("bogus character 0x%02x, ignoring", (int) c );
  179.             continue;
  180.         }
  181.  
  182.         ++imageCount;
  183.  
  184.         if (! ReadOK(fd,buf,9))
  185.             pm_error("couldn't read left/top/width/height");
  186.  
  187.         useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
  188.  
  189.         bitPixel = 1<<((buf[8]&0x07)+1);
  190.  
  191.         if (! useGlobalColormap) {
  192.             if (ReadColorMap(fd, bitPixel, localColorMap))
  193.                 pm_error("error reading local colormap" );
  194.             ReadImage(fd, LM_to_uint(buf[4],buf[5]),
  195.                   LM_to_uint(buf[6],buf[7]), localColorMap,
  196.                   BitSet(buf[8], INTERLACE), imageCount != imageNumber);
  197.         } else {
  198.             ReadImage(fd, LM_to_uint(buf[4],buf[5]),
  199.                   LM_to_uint(buf[6],buf[7]), GifScreen.ColorMap,
  200.                   BitSet(buf[8], INTERLACE), imageCount != imageNumber);
  201.         }
  202.  
  203.     }
  204. }
  205.  
  206. static int
  207. ReadColorMap(fd,number,buffer)
  208. FILE        *fd;
  209. int        number;
  210. unsigned char    buffer[3][MAXCOLORMAPSIZE];
  211. {
  212.     int        i;
  213.     unsigned char    rgb[3];
  214.  
  215.     for (i = 0; i < number; ++i) {
  216.         if (! ReadOK(fd, rgb, sizeof(rgb)))
  217.             pm_error("bad colormap" );
  218.  
  219.         buffer[CM_RED][i] = rgb[0] ;
  220.         buffer[CM_GREEN][i] = rgb[1] ;
  221.         buffer[CM_BLUE][i] = rgb[2] ;
  222.     }
  223.     return FALSE;
  224. }
  225.  
  226. static int
  227. DoExtension(fd, label)
  228. FILE    *fd;
  229. int    label;
  230. {
  231.     static char    buf[256];
  232.     char        *str;
  233.  
  234.     switch (label) {
  235.     case 0x01:        /* Plain Text Extension */
  236.         str = "Plain Text Extension";
  237. #ifdef notdef
  238.         if (GetDataBlock(fd, (unsigned char*) buf) == 0)
  239.             ;
  240.  
  241.         lpos   = LM_to_uint(buf[0], buf[1]);
  242.         tpos   = LM_to_uint(buf[2], buf[3]);
  243.         width  = LM_to_uint(buf[4], buf[5]);
  244.         height = LM_to_uint(buf[6], buf[7]);
  245.         cellw  = buf[8];
  246.         cellh  = buf[9];
  247.         foreground = buf[10];
  248.         background = buf[11];
  249.  
  250.         while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
  251.             PPM_ASSIGN(image[ypos][xpos],
  252.                     cmap[CM_RED][v],
  253.                     cmap[CM_GREEN][v],
  254.                     cmap[CM_BLUE][v]);
  255.             ++index;
  256.         }
  257.  
  258.         return FALSE;
  259. #else
  260.         break;
  261. #endif
  262.     case 0xff:        /* Application Extension */
  263.         str = "Application Extension";
  264.         break;
  265.     case 0xfe:        /* Comment Extension */
  266.         str = "Comment Extension";
  267.         while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
  268.             if (showComment)
  269.                 pm_message("gif comment: %s", buf );
  270.         }
  271.         return FALSE;
  272.     case 0xf9:        /* Graphic Control Extension */
  273.         str = "Graphic Control Extension";
  274.         (void) GetDataBlock(fd, (unsigned char*) buf);
  275.         Gif89.disposal    = (buf[0] >> 2) & 0x7;
  276.         Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
  277.         Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
  278.         if ((buf[0] & 0x1) != 0)
  279.             Gif89.transparent = buf[3];
  280.  
  281.         while (GetDataBlock(fd, (unsigned char*) buf) != 0)
  282.             ;
  283.         return FALSE;
  284.     default:
  285.         str = buf;
  286.         sprintf(buf, "UNKNOWN (0x%02x)", label);
  287.         break;
  288.     }
  289.  
  290.     pm_message("got a '%s' extension", str );
  291.  
  292.     while (GetDataBlock(fd, (unsigned char*) buf) != 0)
  293.         ;
  294.  
  295.     return FALSE;
  296. }
  297.  
  298. int    ZeroDataBlock = FALSE;
  299.  
  300. static int
  301. GetDataBlock(fd, buf)
  302. FILE        *fd;
  303. unsigned char     *buf;
  304. {
  305.     unsigned char    count;
  306.  
  307.     if (! ReadOK(fd,&count,1)) {
  308.         pm_message("error in getting DataBlock size" );
  309.         return -1;
  310.     }
  311.  
  312.     ZeroDataBlock = count == 0;
  313.  
  314.     if ((count != 0) && (! ReadOK(fd, buf, count))) {
  315.         pm_message("error in reading DataBlock" );
  316.         return -1;
  317.     }
  318.  
  319.     return count;
  320. }
  321.  
  322. static int
  323. GetCode(fd, code_size, flag)
  324. FILE    *fd;
  325. int    code_size;
  326. int    flag;
  327. {
  328.     static unsigned char    buf[280];
  329.     static int        curbit, lastbit, done, last_byte;
  330.     int            i, j, ret;
  331.     unsigned char        count;
  332.  
  333.     if (flag) {
  334.         curbit = 0;
  335.         lastbit = 0;
  336.         done = FALSE;
  337.         return 0;
  338.     }
  339.  
  340.     if ( (curbit+code_size) >= lastbit) {
  341.         if (done) {
  342.             if (curbit >= lastbit)
  343.                 pm_error("ran off the end of my bits" );
  344.             return -1;
  345.         }
  346.         buf[0] = buf[last_byte-2];
  347.         buf[1] = buf[last_byte-1];
  348.  
  349.         if ((count = GetDataBlock(fd, &buf[2])) == 0)
  350.             done = TRUE;
  351.  
  352.         last_byte = 2 + count;
  353.         curbit = (curbit - lastbit) + 16;
  354.         lastbit = (2+count)*8 ;
  355.     }
  356.  
  357.     ret = 0;
  358.     for (i = curbit, j = 0; j < code_size; ++i, ++j)
  359.         ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
  360.  
  361.     curbit += code_size;
  362.  
  363.     return ret;
  364. }
  365.  
  366. static int
  367. LWZReadByte(fd, flag, input_code_size)
  368. FILE    *fd;
  369. int    flag;
  370. int    input_code_size;
  371. {
  372.     static int    fresh = FALSE;
  373.     int        code, incode;
  374.     static int    code_size, set_code_size;
  375.     static int    max_code, max_code_size;
  376.     static int    firstcode, oldcode;
  377.     static int    clear_code, end_code;
  378.     static int    table[2][(1<< MAX_LWZ_BITS)];
  379.     static int    stack[(1<<(MAX_LWZ_BITS))*2], *sp;
  380.     register int    i;
  381.  
  382.     if (flag) {
  383.         set_code_size = input_code_size;
  384.         code_size = set_code_size+1;
  385.         clear_code = 1 << set_code_size ;
  386.         end_code = clear_code + 1;
  387.         max_code_size = 2*clear_code;
  388.         max_code = clear_code+2;
  389.  
  390.         GetCode(fd, 0, TRUE);
  391.         
  392.         fresh = TRUE;
  393.  
  394.         for (i = 0; i < clear_code; ++i) {
  395.             table[0][i] = 0;
  396.             table[1][i] = i;
  397.         }
  398.         for (; i < (1<<MAX_LWZ_BITS); ++i)
  399.             table[0][i] = table[1][0] = 0;
  400.  
  401.         sp = stack;
  402.  
  403.         return 0;
  404.     } else if (fresh) {
  405.         fresh = FALSE;
  406.         do {
  407.             firstcode = oldcode =
  408.                 GetCode(fd, code_size, FALSE);
  409.         } while (firstcode == clear_code);
  410.         return firstcode;
  411.     }
  412.  
  413.     if (sp > stack)
  414.         return *--sp;
  415.  
  416.     while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
  417.         if (code == clear_code) {
  418.             for (i = 0; i < clear_code; ++i) {
  419.                 table[0][i] = 0;
  420.                 table[1][i] = i;
  421.             }
  422.             for (; i < (1<<MAX_LWZ_BITS); ++i)
  423.                 table[0][i] = table[1][i] = 0;
  424.             code_size = set_code_size+1;
  425.             max_code_size = 2*clear_code;
  426.             max_code = clear_code+2;
  427.             sp = stack;
  428.             firstcode = oldcode =
  429.                     GetCode(fd, code_size, FALSE);
  430.             return firstcode;
  431.         } else if (code == end_code) {
  432.             int        count;
  433.             unsigned char    buf[260];
  434.  
  435.             if (ZeroDataBlock)
  436.                 return -2;
  437.  
  438.             while ((count = GetDataBlock(fd, buf)) > 0)
  439.                 ;
  440.  
  441.             if (count != 0)
  442.                 pm_message("missing EOD in data stream (common occurence)");
  443.             return -2;
  444.         }
  445.  
  446.         incode = code;
  447.  
  448.         if (code >= max_code) {
  449.             *sp++ = firstcode;
  450.             code = oldcode;
  451.         }
  452.  
  453.         while (code >= clear_code) {
  454.             *sp++ = table[1][code];
  455.             if (code == table[0][code])
  456.                 pm_error("circular table entry BIG ERROR");
  457.             code = table[0][code];
  458.         }
  459.  
  460.         *sp++ = firstcode = table[1][code];
  461.  
  462.         if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
  463.             table[0][code] = oldcode;
  464.             table[1][code] = firstcode;
  465.             ++max_code;
  466.             if ((max_code >= max_code_size) &&
  467.                 (max_code_size < (1<<MAX_LWZ_BITS))) {
  468.                 max_code_size *= 2;
  469.                 ++code_size;
  470.             }
  471.         }
  472.  
  473.         oldcode = incode;
  474.  
  475.         if (sp > stack)
  476.             return *--sp;
  477.     }
  478.     return code;
  479. }
  480.  
  481. static void
  482. ReadImage(fd, len, height, cmap, interlace, ignore)
  483. FILE    *fd;
  484. int    len, height;
  485. unsigned char    cmap[3][MAXCOLORMAPSIZE];
  486. int    interlace, ignore;
  487. {
  488.     unsigned char    c;    
  489.     int        v;
  490.     int        xpos = 0, ypos = 0, pass = 0;
  491.     pixel        **image;
  492.  
  493.     /*
  494.     **  Initialize the Compression routines
  495.     */
  496.     if (! ReadOK(fd,&c,1))
  497.         pm_error("EOF / read error on image data" );
  498.  
  499.     if (LWZReadByte(fd, TRUE, c) < 0)
  500.         pm_error("error reading image" );
  501.  
  502.     /*
  503.     **  If this is an "uninteresting picture" ignore it.
  504.     */
  505.     if (ignore) {
  506.         if (verbose)
  507.             pm_message("skipping image..." );
  508.  
  509.         while (LWZReadByte(fd, FALSE, c) >= 0)
  510.             ;
  511.         return;
  512.     }
  513.  
  514.     if ((image = ppm_allocarray(len, height)) == NULL)
  515.         pm_error("couldn't alloc space for image" );
  516.  
  517.     if (verbose)
  518.         pm_message("reading %d by %d%s GIF image",
  519.             len, height, interlace ? " interlaced" : "" );
  520.  
  521.     while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
  522.         PPM_ASSIGN(image[ypos][xpos], cmap[CM_RED][v],
  523.                     cmap[CM_GREEN][v], cmap[CM_BLUE][v]);
  524.  
  525.         ++xpos;
  526.         if (xpos == len) {
  527.             xpos = 0;
  528.             if (interlace) {
  529.                 switch (pass) {
  530.                 case 0:
  531.                 case 1:
  532.                     ypos += 8; break;
  533.                 case 2:
  534.                     ypos += 4; break;
  535.                 case 3:
  536.                     ypos += 2; break;
  537.                 }
  538.  
  539.                 if (ypos >= height) {
  540.                     ++pass;
  541.                     switch (pass) {
  542.                     case 1:
  543.                         ypos = 4; break;
  544.                     case 2:
  545.                         ypos = 2; break;
  546.                     case 3:
  547.                         ypos = 1; break;
  548.                     default:
  549.                         goto fini;
  550.                     }
  551.                 }
  552.             } else {
  553.                 ++ypos;
  554.             }
  555.         }
  556.         if (ypos >= height)
  557.             break;
  558.     }
  559.  
  560. fini:
  561.     if (LWZReadByte(fd,FALSE,c)>=0)
  562.         pm_message("too much input data, ignoring extra...");
  563.  
  564.     if (verbose)
  565.         pm_message("writing output");
  566.     ppm_writeppm(stdout, image, len, height, (pixval) 255, 0 );
  567. }
  568.